<?php

namespace common\service;

use common\exception\LogicException;
use common\model\EntityModel;
use common\model\EntityRelationshipsModel;
use common\model\MediaModel;
use common\model\OrderModel;
use common\model\OrderTaskListModel;
use common\model\OrderTaskUpstreamVersionModel;
use common\model\ProjectModel;
use common\model\ProjectRelationTemplateTodoModel;
use common\model\ProjectTemplateModel;
use common\model\StepCategoryModel;
use common\model\StepUpstreamModel;
use common\model\StepWorkflowModel;
use common\model\TaskMemberModel;
use common\model\TaskModel;
use common\model\TaskRelationModel;
use common\model\TaskRelationTagModel;
use common\model\UserModel;
use common\model\VersionModel;
use support\Db;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;
use think\module\Module;

class TaskUpstreamService
{
    use SingletonTrait;

    private $taskModel;

    public function __construct()
    {
        $this->taskModel = model(TaskModel::class);
    }

    /**
     * 查询上游实体列表 通过关联关系获取
     * @param $entityId
     * @return array
     */
    public function getUpstreamEntityList($entityId): array
    {
        $relatedEntities = [];
        $entity = model(EntityModel::class)->find($entityId);
        // 实体不存在那么 返回空数组
        if (empty($entity)) {
            return $relatedEntities;
        }
        $relatedEntities = [$entityId];
        switch ($entity['module_id']) {
            case Module::$moduleDictData['module_index_by_code']['shot']['id']:
                /**
                 * 序列也是镜头的关联
                 */
                if ($entity['entity_id'] > 0) {
                    $relatedEntities[] = $entity['entity_id'];
                }
                break;
            default:
        }
        $sources = TemplateService::getInstance()->getModuleSources($entity['project_id'], $entity['module_id']);
        /**
         * 上游
         * 当前实体关联的数据
         * current_module_code_relation_source_code
         * etc: level_asset
         */
        $sourceStepCategories = model(StepCategoryModel::class)
            ->where(['id' => ['IN', implode(',', $sources)]])
            ->select();
        $moduleCode = Module::$moduleDictData['module_index_by_id'][$entity['module_id']]['code'];
        $entity['json'] = json_decode($entity['json'], true);
        foreach ($sourceStepCategories as $sourceStepCategory) {
            $relateFieldName = "{$moduleCode}_{$sourceStepCategory['code']}";
            APP_DEBUG && trace("START FIND $relateFieldName IN {$entity['name']}", 'DEBUG');
            $relationEntityStr = $entity['json'][$relateFieldName] ?? "";
            APP_DEBUG && trace("FIND {$relationEntityStr}", 'DEBUG');
            $tmpRelatedEntities = explode(',', $relationEntityStr);
            $tmpRelatedEntities = array_filter($tmpRelatedEntities, function ($item) {
                return intval($item) > 0;
            });
            if (count($tmpRelatedEntities) == 0) {
                continue;
            }
            $relatedEntities = array_merge($relatedEntities, $tmpRelatedEntities);
        }
        return $relatedEntities;
    }

    /**
     * 获得上游任务列表
     * @param int $taskId
     * @param bool $outSide 是否使用outside工序上游配置表
     * @param bool $onlyRelativeNo 只要非关联性的任务
     * @param bool $closeShow 是否显示已取消任务
     * @param bool $onlyRelateAsset
     * @param bool $crontab 是否脚本调用
     * @return array
     * @throws \Exception
     */
    public function getUpstreamTaskList(int $taskId, $outSide = false, $onlyRelativeNo = false, $closeShow = false, $onlyRelateAsset = false, $crontab = false)
    {
        $task = $this->taskModel->find($taskId);
        $taskJsonToArray = json_decode($task['json'] ?? '{}', true);

        // 任务关系转换,子任务,转换成父任务
        $task = DismantleTaskService::getInstance()->dismantleTaskTransformation($task);
        if (empty($task)) {
            throw new LogicException("can`t found task", ErrorCode::TASK_NOT_FOUND);
        }
        $taskList = [];

        $project = model(ProjectModel::class)->where(['id' => $task['project_id']])->field('type,project_template_id')->cache(C('database.default_query_cache_time'))->find();
        $projectType = $project['type'] ?? null;
        if ($projectType === 'outsource') {
            $orderService = OrderService::getInstance();
            $partyATask = $orderService->getSourceTaskByTaskId($task['id']);
            if (!empty($partyATask)) {
                $task = $partyATask;
            }
        }
        $entityIdList = $this->getUpstreamEntityList($task['entity_id']);

        if ($onlyRelateAsset) {
            $entityIdList = array_filter($entityIdList, function ($i) use ($task) {
                return $i != $task['entity_id'];
            });
        }
        if (empty($entityIdList)) {
            return $taskList;
        }
        $stepService = StepService::getInstance();
        $upstreamSteps = [];
        if ($outSide) {
            $upstreamSteps = $stepService->getStepUpstreamOutside($task['step_id']);
        } else {
            $projectTemplateId = TaskService::getInstance()->getTaskProjectTemplateId($task['id']);
            if (empty($taskJsonToArray['step_workflow_id'])) {
                $upstreamSteps = $stepService->getStepUpstream($task['step_id'], $projectTemplateId, 0);
            }
            // 新工序流
            if (!empty($taskJsonToArray['step_workflow_id'])) {
                $upstreamSteps = $stepService->getStepUpstream($task['step_id'], 0, $task['project_id'], $taskJsonToArray['step_workflow_id']);
            }
        }

        if (empty($upstreamSteps)) {
            return $taskList;
        }
        $stepIdList = array_column($upstreamSteps, 'step_id', 'step_id');
        $stepRelativeMap = array_column($upstreamSteps, 'relevance', 'step_id');
        $taskList = $this->taskModel
            ->where([
                'entity_id' => ['IN', implode(',', $entityIdList)],
                'step_id' => ['IN', implode(',', $stepIdList)],
            ])
            ->select();
        if (!$closeShow) {
            $closedStatus = StatusService::getInstance()->getOne(['code' => 'closed'], '*');
            $closedStatusId = $closedStatus['id'];
            $taskList = array_filter($taskList, function ($task) use ($closedStatusId) {
                $jsonFields = json_decode($task['json'], true);
                return $jsonFields['task_status'] != $closedStatusId;
            });
            $taskList = array_values($taskList);
        }
        //整理数组
        return $this->clearTaskUpstreamData($taskList, $onlyRelativeNo, $stepRelativeMap);
    }


    /**
     * 查询上游任务
     * @param $taskId
     * @return array|mixed|string
     */
    public function getUpstreamTaskListV2($taskId, $closeShow = false)
    {
        $task = $this->taskModel->find($taskId);
        // 任务关系转换,子任务,转换成父任务
        $task = DismantleTaskService::getInstance()->dismantleTaskTransformation($task);
        if (empty($task)) {
            throw new LogicException("can`t found task", ErrorCode::TASK_NOT_FOUND);
        }
        $project = model(ProjectModel::class)->where(['id' => $task['project_id']])->field('type,project_template_id')->cache(C('database.default_query_cache_time'))->find();
        $projectType = $project['type'] ?? null;
        if ($projectType === 'outsource') {
            $partyATask = OrderService::getInstance()->getSourceTaskByTaskId($task['id']);
            if (!empty($partyATask)) {
                $task = $partyATask;
            }
        }
        $projectId = $task['project_id'] ?? 0;
        $taskList = model(TaskRelationModel::class)
            ->setSuffix(sprintf('_project_%d', $projectId))
            ->alias('task_relation')
            ->join('task on task.id = task_relation.target_task_id')
            ->where(['task_relation.source_task_id' => $task['id']])
            ->where(['task_relation.relation_type' => ['IN', TaskRelationModel::RELATION_TYPE]])
            ->field('task.*,task_relation.relation_type,task_relation.relation')
            ->select();
        if (empty($taskList)) {
            return [];
        }
        if (!$closeShow) {
            $closedStatus = StatusService::getInstance()->getOne(['code' => 'closed'], '*');
            $closedStatusId = $closedStatus['id'];
            $taskList = array_filter($taskList, function ($task) use ($closedStatusId) {
                $jsonFields = json_decode($task['json'], true);
                return $jsonFields['task_status'] != $closedStatusId;
            });
            $taskList = array_values($taskList);
        }
        return array_map(function ($tmp) {
            $upstreamRelevance = 'no';
            if (!empty($tmp['relation_type'])) {
                // 关联类型为关联
                // 关联类型为实体，上游关系为交付
                if ($tmp['relation_type'] == TaskRelationModel::RELATION_TYPE_RELATION
                    || ($tmp['relation_type'] == TaskRelationModel::RELATION_TYPE_ENTITY && $tmp['relation'] == 'delivery')) {
                    $upstreamRelevance = 'yes';
                }
            }
            $tmp['upstream_relevance'] = $upstreamRelevance;
            return $tmp;
        }, $taskList);
    }


    /**
     * 整理任务上游数据
     * @param array $taskList 任务列表
     * @param bool $onlyRelativeNo 只要非关联性的
     * @param array $stepRelativeMap 工序列表
     * @return array
     */
    private function clearTaskUpstreamData(array $taskList, bool $onlyRelativeNo, array $stepRelativeMap)
    {
        foreach ($taskList as &$item) {
            $item['upstream_relevance'] = $stepRelativeMap[$item['step_id']] ?? 'no';
        }
        if ($onlyRelativeNo) {
            $taskList = array_filter($taskList, function ($i) {
                return $i['upstream_relevance'] === 'no';
            });
            $taskList = array_values($taskList);
        }
        return $taskList;
    }

    /**
     * 获取标准任务模板的上下游任务id
     * @param $task
     * @param $templateTodoId
     * @return array|array[]
     */
    public function getStandardTempLateTaskUpstreamInfo($task, $templateTodoId)
    {
        if (empty($task['step_id'])) {
            return [];
        }
        // 1.查询标准任务模板列表
        $templateTodoList = model(ProjectRelationTemplateTodoModel::class)
            ->field('upstream_downstream_template')
            ->where(['template_todo_id' => $templateTodoId, 'project_id' => $task['project_id']])->find();
        if (empty($templateTodoList)) {
            return [];
        }
        // 1.2 处理 所有标准任务模板列表下的上下游关系配置
        $upstreamDownstreamTemplateList = json_decode($templateTodoList['upstream_downstream_template'] ?? '{}', true);
        $toDoTargetIdList = []; // 上游标准任务列表
        $stepTargetIdList = []; // 上游工序任务列表
        $allTargetIdList = []; // 所有上游任务列表

        $allSourceIdList = []; // 所有下游任务列表
        $stepSourceIdList = []; // 上游工序任务列表
        $toDoSourceIdList = []; // 下游标准任务列表
        foreach ($upstreamDownstreamTemplateList as $upstreamDownstreamTemplateItem) {
            foreach ($upstreamDownstreamTemplateItem['upstream_task'] ?? [] as $upstreamTaskItem) {
                // 2. 查询 source_id = 当前任务的 target_id
                if (!empty($upstreamTaskItem['source_id']) && $upstreamTaskItem['source_id'] == $task['step_id']) {
                    if (!empty($upstreamTaskItem['task_type']) && $upstreamTaskItem['task_type'] == 'to_do') { // 模板待办
                        $toDoTargetIdList[] = $upstreamTaskItem;
                    }
                    if (!empty($upstreamTaskItem['task_type']) && $upstreamTaskItem['task_type'] == 'step') { // 工序
                        $stepTargetIdList[] = $upstreamTaskItem;
                    }
                    $allTargetIdList[] = $upstreamTaskItem;
                }
                // 3. 查询 target_id = 当前任务的 source_id
                if (!empty($upstreamTaskItem['target_id']) && $upstreamTaskItem['target_id'] == $task['step_id']) {
                    if (!empty($upstreamTaskItem['task_type']) && $upstreamTaskItem['task_type'] == 'to_do') { // 模板待办
                        $toDoSourceIdList[] = $upstreamTaskItem;
                    }
                    if (!empty($upstreamTaskItem['task_type']) && $upstreamTaskItem['task_type'] == 'step') { // 工序
                        $stepSourceIdList[] = $upstreamTaskItem;
                    }
                    $allSourceIdList[] = $upstreamTaskItem;
                }
            }
        }
        return [
            'step_target_id_list' => $stepTargetIdList,
            'to_do_target_id_list' => $toDoTargetIdList,
            'all_target_id_list' => $allTargetIdList,
            'step_source_id_list' => $stepSourceIdList,
            'to_do_source_id_list' => $toDoSourceIdList,
            'all_source_id_list' => $allSourceIdList,
        ];
    }

    /**
     * 查询上游文件下载信息
     * @param $taskId
     * @return array
     * @throws \Exception
     */
    public function getUpstreamLatestFileShareInfo($taskId): array
    {
        $task = $this->taskModel->where(['id' => $taskId, 'step_type' => 'step'])->find();
        if (empty($task)) {
            throw new LogicException("can`t found task", ErrorCode::TASK_NOT_FOUND);
        }
        $project = model(ProjectModel::class)->where(['id' => $task['project_id']])->find();
        if ($project['type'] === 'outsource') {
            // 外部项目
            // 查询原始任务
            $orderService = OrderService::getInstance();
            $task = $orderService->getSourceTaskByTaskId($taskId);
            if (empty($task)) {
                // 没有原始任务 直接返回空列表 不需要下载文件
                return [];
            }
        }
        $upstreamTaskList = [];
        $task['json'] = json_decode($task['json'], true);
        if (empty($task['json']['step_workflow_id'])) {
            $upstreamTaskList = $this->getUpstreamTaskList($task['id']);
        }
        if (!empty($task['json']['step_workflow_id'])) {
            $upstreamTaskList = $this->getUpstreamTaskListV2($task['id']);
        }
        if (empty($upstreamTaskList)) {
            return [];
        }
        // 查询所有任务的最新版本下载文件
        // 查询所有上游任务的最新版本
        $upstreamTaskIdList = array_column($upstreamTaskList, 'id');
        $versionFileStorageInfoList = VersionService::getInstance()->getMaxTaskListVersionList($upstreamTaskIdList);
        if (empty($versionFileStorageInfoList)) {
            throw_strack_exception('did not found latest uploaded upstream task version', ErrorCode::TASK_VERSION_NOT_FOUND);
        }
        $leastCount = count($upstreamTaskList) - count($versionFileStorageInfoList);
        if ($leastCount !== 0) {
            throw_strack_exception("has {$leastCount} task did not found uploaded latest version", ErrorCode::TASK_VERSION_NOT_FOUND);
        }
        return $versionFileStorageInfoList;
    }

    /**
     * 获得下游任务列表
     * @param $taskId
     * @param bool $onlyStarted 是否只查询已开始的任务
     * @return array|false|mixed|string
     */
    public function getDownstreamTaskList($taskId, $onlyStarted = false)
    {
        $task = $this->taskModel->find($taskId);
        $taskData = json_decode($task['json'], true);
        $task['step_workflow_id'] = $taskData['step_workflow_id'] ?? 0;
        if (empty($task)) {
            throw new LogicException("can`t found task", ErrorCode::TASK_NOT_FOUND);
        }
        if ($onlyStarted) {
            $statusFilter = [];
            $statusService = StatusService::getInstance();
            $defaultStatus = $statusService->getTaskDefaultStatus();
            if (!empty($defaultStatus)) {
                $statusFilter[] = $defaultStatus['id'];
            }
            $defaultWaitAssembleStatus = $statusService->getTaskWaitAssembleStatus();
            if (!empty($defaultWaitAssembleStatus)) {
                $statusFilter[] = $defaultWaitAssembleStatus['id'];
            }
            $defaultReadyStatus = $statusService->getTaskDefaultReadyStatus();
            if (!empty($defaultReadyStatus)) {
                $statusFilter[] = $defaultReadyStatus['id'];
            }
        }
        $taskList = [];
        // 如果是新工序流
        if (!empty($task['step_workflow_id'])) {
            $upstreamTaskIds = [];
            $upstreamTaskList = TaskUpstreamService::getInstance()->getStepUpDownstreamTaskList($taskId, 'downstream');
            if (!empty($upstreamTaskList)) {
                foreach ($upstreamTaskList as $upstreamTaskItem) {
                    $upstreamTaskIds[] = $upstreamTaskItem['upstream_task_id'];
                }
                $query = $this->taskModel
                    ->where(['id' => ['IN', $upstreamTaskIds]]);
                // 状态筛选
                if (!empty($statusFilter)) {
                    $query = $query->where("JSON_UNQUOTE(JSON_EXTRACT(json,'$.task_status')) not in (" . implode(',', $statusFilter) . ")");
                }
                return $query->select();
            }
        }
        $entityIdList = EntityUpstreamService::getInstance()->getDownstreamEntityList($task['entity_id']);
        // 把当前实体添加到关联实体列表中
        $entityIdList[] = $task['entity_id'];
        if (!empty($entityIdList)) {
            $stepService = StepService::getInstance();
            $upstreamSteps = $stepService->getStepDownstream($task['step_id']);
            if (!empty($upstreamSteps)) {
                $stepIdList = array_column($upstreamSteps, 'step_id', 'step_id');
                $query = $this->taskModel
                    ->where([
                        'entity_id' => ['IN', implode(',', $entityIdList)],
                        'step_id' => ['IN', implode(',', $stepIdList)],
                    ]);
                // 状态筛选
                if (!empty($statusFilter)) {
                    $query = $query->where("JSON_UNQUOTE(JSON_EXTRACT(json,'$.task_status')) not in (" . implode(',', $statusFilter) . ")");
                }
                $taskList = $query->select();
            }
        }
        return $taskList;
    }

    /**
     * 查询受影响任务数量
     * @param $id
     * @return int
     */
    public function getEffectedTaskCount($id): int
    {
        $taskList = $this->getDownstreamTaskList($id);
        return count($taskList);
    }

    /**
     * 任务上游关系查询
     * @param $param
     * @return array
     * @throws Exception
     * @throws \Exception
     */
    public function getUpstreamRelationInfo($param): array
    {
        /**
         * 1. 查询处所有的上游任务
         * 2. 转换上游任务信息 构建出需要下载的任务
         * 2.1 甲方  查看上游任务是否有被外包 外包的任务替换为乙方任务id 加入需要下载的任务列表
         * 2.2 乙方  查看上游任务是否被发给当前制作公司 从需要下载的任务列表移除
         * 3. 查询需要下载任务的 最新下载记录
         * 4. 查询上游任务的最新已发布版本记录
         * 5. 组装查询结果
         */
        $filter = $param['filter'];
        $fields = $param['fields'] ?? null;
        $versionFields = "id,link_id,number,description,json,json->>'$.version_media' version_media_ids";
        $task = $this->taskModel->where($filter)->find();
        if (empty($task)) {
            throw_strack_exception("task not found", ErrorCode::TASK_NOT_FOUND);
        }
        $task['json'] = json_decode($task['json'], true);
        $project = model(ProjectModel::class)->field('type')->find($task['project_id']);
        $projectType = $project['type'] ?? null;
        $isOutside = $projectType === 'outsource';

        $taskId = $task['id'];
        if ($projectType === 'outsource') {
            // 如果是外包任务转换成甲方任务id查询
            $orderService = OrderService::getInstance();
            $partyATask = $orderService->getSourceTaskByTaskId($taskId);
            if (!empty($partyATask)) {
                $taskId = $partyATask['id'];
            }
        }

        $upstreamTaskList = $this->getUpstreamTaskList($taskId);

        // 如果是标准任务,且没查到上下游，就返回空
        if (in_array($task['step_type'], ['standard_meeting', 'standard_review', 'standard_make_to_do', 'to_do']) && empty($upstreamTaskList)) {
            return [];
        }
        $upstreamTaskIdList = array_values(array_column($upstreamTaskList, 'id', 'id'));
        $needDownloadTaskList = [];
        // 如若是外包
        if ($isOutside && !empty($upstreamTaskIdList)) {
            $needDownloadTaskList = $upstreamTaskIdList;
            // 上游任务id的转换
            $orderTaskListFilter = ['order_task_list.task_id' => ['IN', $upstreamTaskIdList], 'o.to_tenant_id' => $task['tenant_id'], 'order_task_list.status' => OrderTaskListModel::STATUS_DEFAULT];
            $orderTaskList = model(OrderTaskListModel::class)->join('`order` o on o.id = order_task_list.order_id')->where($orderTaskListFilter)->field('order_task_list.*')->select();
            if (!empty($orderTaskList)) {
                $orderTaskListMap = array_column($orderTaskList, 'real_task_id', 'task_id');
                foreach ($upstreamTaskIdList as $k => $upstreamTaskId) {
                    if (isset($orderTaskListMap[$upstreamTaskId])) {
                        $upstreamTaskIdList[$k] = $orderTaskListMap[$upstreamTaskId];
                        unset($needDownloadTaskList[$k]);
                    }
                }
            }
        } else if (!$isOutside && !empty($upstreamTaskIdList)) {
            // 筛选被外包的任务 然后替换为乙方的任务id
            $upstreamTaskBeSendOutList = array_filter($upstreamTaskList, function ($taskItem) {
                return in_array($taskItem['executor_type'], TaskModel::OUTSIDE_EXECUTE_TYPE_GROUP);
            });
            if (!empty($upstreamTaskBeSendOutList)) {
                $orderTaskListFilter = [
                    'order_task_list.task_id' => ['IN', array_column($upstreamTaskBeSendOutList, 'id')],
                    'o.from_tenant_id' => $task['tenant_id'],
                    'order_task_list.status' => OrderTaskListModel::STATUS_DEFAULT
                ];
                $orderTaskList = model(OrderTaskListModel::class)
                    ->join('`order` o on o.id = order_task_list.order_id')
                    ->where($orderTaskListFilter)
                    ->field('order_task_list.*')
                    ->select();
                if (!empty($orderTaskList)) {
                    $orderTaskListMap = array_column($orderTaskList, 'real_task_id', 'task_id');
                    foreach ($upstreamTaskIdList as $k => $upstreamTaskId) {
                        if (isset($orderTaskListMap[$upstreamTaskId]) && $orderTaskListMap[$upstreamTaskId] > 0) {
                            $upstreamTaskIdList[$k] = $orderTaskListMap[$upstreamTaskId];
                            $needDownloadTaskList[] = $upstreamTaskIdList[$k];
                        }
                    }
                }
            }
        }
        // 查询需要下载任务的最新下载记录
        $downloadedVersionMap = [];
        if (count($needDownloadTaskList)) {
            $taskUpstreamTaskStatusFilter = [
                'task_id' => ['IN', implode(',', $needDownloadTaskList)],
                'to_tenant_id' => $task['tenant_id'],
                'is_download' => 'yes',
            ];
            $downloadVersionInfoList = model(OrderTaskUpstreamVersionModel::class)
                ->where($taskUpstreamTaskStatusFilter)->group('task_id')
                ->field('max(version_id) as version_id')->select();
            if (!empty($downloadVersionInfoList)) {
                $downloadedVersionList = model(VersionModel::class)
                    ->where(['id' => ['IN', implode(',', array_column($downloadVersionInfoList, 'version_id'))]])
                    ->field($versionFields)->select();
                $downloadedVersionMap = array_column($downloadedVersionList, null, 'link_id');
            }
        }
        // 查询上游任务的最新版本信息
        $latestVersionMap = [];
        if (!empty($upstreamTaskIdList)) {
            $latestVersionListFilter = [
                'module_id' => module_by_code('task')['id'],
                'link_id' => ['IN', implode(',', $upstreamTaskIdList)],
                'is_publish' => 'yes',
            ];
            $latestVersionList = model(VersionModel::class)
                ->where($latestVersionListFilter)
                ->field('max(id) as id')->group('link_id')->select();
            if (!empty($latestVersionList)) {
                $latestVersionMap = model(VersionModel::class)
                    ->where(['id' => ['IN', array_column($latestVersionList, 'id')]])
                    ->field($versionFields)
                    ->select();
                $latestVersionMap = array_column($latestVersionMap, null, 'link_id');
            }
        }
        if (empty($fields)) {
            $fields = [
                'entity.id', 'entity.name', 'entity.initial_episode_code', 'entity.showings_number', 'entity.json',
                'step.id', 'step.name', 'step.code',
                'status.id', 'status.name', 'status.code', 'status.color',
                'task.id', 'task.name', 'task.code', 'task.is_assemble', 'task.executor_tenant_id', 'task.executor', 'task.plan_start_time', 'task.plan_end_time',
                'task.step_type',
                'module.code',
                'step_category.id', 'step_category.name'
            ];
        } else {
            $fields = explode(',', $fields);
        }
        $upstreamTaskUserMap = [];
        $upstreamTaskRelationStepCategoryMap = []; // 上游任务关联环节
        if (!empty($upstreamTaskIdList)) {
            // 查询上游任务用户
            $upstreamTaskUserList = model(TaskMemberModel::class)
                ->join('user on user.id = task_member.user_id')
                ->field('task_member.user_id,task_member.task_id,user.avatar,user.name,task_member.status')
                ->where(['task_member.task_id' => ['IN', $upstreamTaskIdList]])
                ->select();
            $upstreamTaskUserMap = array_group_by($upstreamTaskUserList, 'task_id');

            // 上游任务关联环节
            $upstreamTaskRelationStepCategoryInfo = model(TaskRelationTagModel::class)
                ->where(['task_id' => ['IN', $upstreamTaskIdList], 'link_module_code' => ['IN', ['step_category', 'show_step_category']]])
                ->field(['link_id', 'task_id'])
                ->select();
            //环节详情
            if (!empty($upstreamTaskRelationStepCategoryInfo)) {
                $showStepCategoryList = TemplateService::getInstance()->findStepCategoryShowList();
                $showStepCategoryMap = array_column($showStepCategoryList, null, 'id');
                foreach ($upstreamTaskRelationStepCategoryInfo as $upstreamTaskRelationStepCategoryItem) {
                    if (!empty($showStepCategoryMap[$upstreamTaskRelationStepCategoryItem['link_id']])) {
                        $upstreamTaskRelationStepCategoryMap[$upstreamTaskRelationStepCategoryItem['task_id']][] = $showStepCategoryMap[$upstreamTaskRelationStepCategoryItem['link_id']];
                    }
                }
            }
        }
        $taskListIdList = $upstreamTaskIdList;
        $taskListIdList[] = $task['id'];
        $taskListFilter = ['task.id' => ['IN', $taskListIdList]];
        $taskList = $this->taskModel
            ->join('entity ON entity.id = task.entity_id', 'LEFT')
            ->join('module ON entity.module_id = module.id', 'LEFT')
            ->join('status ON status.id = JSON_UNQUOTE(JSON_EXTRACT(task.json,\'$.task_status\'))', 'LEFT')
            ->join('step ON task.step_id = step.id', 'LEFT')
            ->join('step_category ON task.step_category_id = step_category.id', 'LEFT')
            ->where($taskListFilter)->field(build_complex_query_fields($fields, '__'))->select();
        $taskList = array_column($taskList, null, 'task__id');
        $taskUpstreamTaskStatus = [];
        //如若是外包,需要判断任务的组装情况
        if ($isOutside && !empty($upstreamTaskIdList)) {
            $taskUpstreamTaskStatusFilter = ['task_id' => ['IN', $upstreamTaskIdList], 'to_tenant_id' => $task['tenant_id'], 'is_assemble' => 'yes'];
            $taskUpstreamTaskStatus = model(OrderTaskUpstreamVersionModel::class)->where($taskUpstreamTaskStatusFilter)->field('task_id')->select();
            $taskUpstreamTaskStatus = array_column($taskUpstreamTaskStatus, 'task_id', 'task_id');
        }
        //需要判断上游任务执行人员是否是自己公司的,则显示其他人员的公司名字
        $taskExecutorMap = [];
        $taskTenantMap = [];
        $supplierRes = [];
        $needQueryRelateTodoTaskEntityIdList = [];
        $needQueryTodoTaskEntityIdList = [];
        $texStepCode = OptionsService::getInstance()->getTexStepCode();
        foreach ($taskList as $taskListItem) {
            if ($taskListItem['task__executor_tenant_id'] > 0) {
                if ($taskListItem['task__executor_tenant_id'] != $task['tenant_id']) {
                    $taskTenantMap[$taskListItem['task__id']] = $taskListItem['task__executor_tenant_id'];
                } elseif ($taskListItem['task__executor'] > 0) {
                    $taskExecutorMap[$taskListItem['task__id']] = $taskListItem['task__executor'];
                }
            }
            if ($task['entity_id'] != $taskListItem['entity__id']
                && in_array($taskListItem['step__code'], $texStepCode)
            ) {
                // 跨环节的关联查询
                // 需要查询关联的指定衍生贴图
                $needQueryRelateTodoTaskEntityIdList[$taskListItem['entity__id']] = $taskListItem['entity__id'];
            } else if (
                $task['id'] != $taskListItem['task__id']
                && $task['entity_id'] == $taskListItem['entity__id']
                && in_array($taskListItem['step__code'], $texStepCode)) {
                // 本环节实体的衍生贴图查询
                $needQueryTodoTaskEntityIdList[] = $taskListItem['entity__id'];
            }
        }
        //查询出相关租户信息
        if (!empty($taskTenantMap)) {
            // todo 租户不是自己的供应商 会查询不出来
            $supplierRes = TaskService::getInstance()->queryTaskSupplierInfo($task['tenant_id'], [], array_unique(array_values($taskTenantMap)));
        }
        $user = [];
        if (!empty($taskExecutorMap)) {
            $user = model(UserModel::class)->where(['id' => ['IN', join(',', $taskExecutorMap)]])->field(['user.id', 'user.name', 'user.union_id', 'user.avatar',])->select();
            $user = array_column($user, null, 'id');
        }
        $itemCallback = function ($item) use ($taskExecutorMap, $user, $latestVersionMap, $needDownloadTaskList, $downloadedVersionMap) {
            $item = separate_complex_query_data($item, '__');
            //补充用户
            if (isset($taskExecutorMap[$item['task']['id']]) && isset($user[$taskExecutorMap[$item['task']['id']]])) {
                $item['user'] = $user[$taskExecutorMap[$item['task']['id']]];
                $item['user']['type'] = 'user';
            }
            $taskId = $item['task']['id'];
            $item['download_version'] = $item['latest_version'] = $latestVersionMap[$taskId] ?? null;
            if (in_array($taskId, $needDownloadTaskList)) {
                // 需要下载的上游任务
                $item['download_version'] = $downloadedVersionMap[$taskId] ?? null;
            }
            $entityJson = json_decode($item['entity']['json'], true);
            $gradeKey = $item['module']['code'] . '_' . 'grade';
            $categoryKey = $item['module']['code'] . '_' . 'category';
            $item['entity']['json'] = $entityJson;
            $item['entity']['grade'] = $entityJson[$gradeKey] ?? null;
            $item['entity']['asset_category'] = $entityJson[$categoryKey] ?? null;
            unset($item['entity']['json']);
            return $item;
        };
        // 外部任务的上游组装状态 由order_task_upstream_version记录
        if ($isOutside) {
            $dealItemCallback = $itemCallback;
            $itemCallback = function ($item) use ($dealItemCallback, $upstreamTaskIdList, $taskUpstreamTaskStatus, $supplierRes) {
                $item = $dealItemCallback($item);
                //补充租户
                if (isset($supplierRes['outside'][$item['task']['executor_tenant_id']])) {
                    $tenantInfo = $supplierRes['outside'][$item['task']['executor_tenant_id']];
                    $item['user'] = ['id' => $tenantInfo['id'], 'name' => $tenantInfo['name'], 'avatar' => "", 'type' => 'tenant'];
                }
                $taskId = $item['task']['id'];
                if (in_array($taskId, $upstreamTaskIdList)) {
                    $item['task']['is_assemble'] = in_array($taskId, $taskUpstreamTaskStatus) ? 'yes' : 'no';
                }
                return $item;
            };
        }
        $taskList = array_map($itemCallback, $taskList);

        $res = $taskList[$task['id']];
        unset($taskList[$task['id']]);
        $res['upstream'] = array_values($taskList);
        // 当前任务实体贴图查询
//        if (!empty($res['step']['code'])
//            && in_array($res['step']['code'], $texStepCode)) {
//            // 当前任务
//            $entityTodoTaskList = $this->getUpstreamTodoTaskList($task, $fields, $itemCallback);
//            if (!empty($entityTodoTaskList)) {
//                $res['relate_todo_task'] = $entityTodoTaskList;
//            }
//        }
        // 上游本环节贴图查询
//        if (!empty($needQueryTodoTaskEntityIdList)) {
//            $entityUpstreamTodoTaskList = $this->batchGetUpstreamTodoTaskList($needQueryTodoTaskEntityIdList, $fields, $itemCallback);
//            if (!empty($entityUpstreamTodoTaskList)) {
//                foreach ($res['upstream'] as &$upstreamTaskItem) {
//                    if (in_array($upstreamTaskItem['step']['code'], $texStepCode) && array_key_exists($upstreamTaskItem['entity']['id'], $entityUpstreamTodoTaskList)) {
//                        $upstreamTaskItem['relate_todo_task'] = $entityUpstreamTodoTaskList[$upstreamTaskItem['entity']['id']];
//                    }
//                }
//            }
//        }
        // 关联贴图查询
//        if (!empty($needQueryRelateTodoTaskEntityIdList)) {
//            $relateUpstreamTodoTaskList = $this->batchGetRelatedUpstreamTodoTaskList($task['entity_id'], $needQueryRelateTodoTaskEntityIdList, $fields, $itemCallback);
//            if (!empty($relateUpstreamTodoTaskList)) {
//                foreach ($res['upstream'] as &$upstreamTaskItem) {
//                    if (in_array($upstreamTaskItem['step']['code'], $texStepCode) && array_key_exists($upstreamTaskItem['entity']['id'], $relateUpstreamTodoTaskList)) {
//                        $upstreamTaskItem['relate_todo_task'] = $relateUpstreamTodoTaskList[$upstreamTaskItem['entity']['id']];
//                    }
//                }
//            }
//        }
        $versionMediaMap = [];
        if (!empty($latestVersionMap)) {
            $mediaIdList = [];
            $vmMap = [];
            foreach ($latestVersionMap as $versionItem) {
                foreach (explode(',', $versionItem['version_media_ids']) as $mediaId) {
                    if (empty($mediaId)) {
                        continue;
                    }
                    $mediaIdList[] = $mediaId;
                    $vmMap[$versionItem['id']][] = $mediaId;
                }
            }
            if (!empty($mediaIdList)) {
                $mediaParam['fields'] = "media.id,media.thumb,media.type,media.param";
                $versionMediaData = model(MediaModel::class)
                    ->where(['id' => ['IN', $mediaIdList]])
                    ->field($mediaParam['fields'])
                    ->select();
                $versionMediaData = array_column($versionMediaData, null, 'id');
                foreach ($vmMap as $versionId => $mediaIdList) {
                    foreach ($mediaIdList as $mediaId) {
                        if (!isset($versionMediaData[$mediaId])) {
                            continue;
                        }
                        $versionMediaData[$mediaId]['param'] = json_decode($versionMediaData[$mediaId]['param'], true);
                        $versionMediaMap[$versionId][] = $versionMediaData[$mediaId];
                    }
                }
            }
        }
        // 上游类型处理
        $stepRelevance = array_column($upstreamTaskList, 'upstream_relevance', 'step_id');
        if (!empty($res['upstream'])) {
            foreach ($res['upstream'] as &$upstreamItem) {
                if (!empty($stepRelevance[$upstreamItem['step']['id']])
                    && $stepRelevance[$upstreamItem['step']['id']] == 'yes') {
                    $upstreamItem['upstream_type'] = '关联任务';
                } else {
                    $upstreamItem['upstream_type'] = '上游任务';
                }
                $upstreamItem['upstream_media'] = null;
                if (!empty($upstreamItem['latest_version']['id']) && !empty($versionMediaMap[$upstreamItem['latest_version']['id']][0])) {
                    $upstreamItem['upstream_media'] = $versionMediaMap[$upstreamItem['latest_version']['id']][0];
                }
                $upstreamItem['task_member'] = $upstreamTaskUserMap[$upstreamItem['task']['id']] ?? [];
                $upstreamItem['relation_step_category_info'] = $upstreamTaskRelationStepCategoryMap[$upstreamItem['task']['id']] ?? [];
            }
        }
        return $res;
    }

    /**
     * 查询任务上游任务的完成状态
     * @param $task
     * @return array
     * @throws Exception|\Exception
     */
    public function getUpstreamTaskDoneStatus($task)
    {
        $task['json'] = json_decode($task['json'], true);
        if (empty($task['json']['step_workflow_id'])) {
            $upstreamTaskList = $this->getUpstreamTaskList($task['id']);
        }
        if (!empty($task['json']['step_workflow_id'])) {
            $upstreamTaskList = $this->getUpstreamTaskListV2($task['id']);
        }

        //$needDownloadCount = 0;
        $totalUpstreamTaskCount = 0;
        $needDownloadRelevantCount = $needDownloadUnRelevantCount = 0;
        $relevanceUndoneCount = $unRelevanceUndoneCount = 0;
        $insideUpstreamTaskList = [];

        if (!empty($upstreamTaskList)) {

            $relevanceStepMap = array_column($upstreamTaskList, 'upstream_relevance', 'step_id');
            $totalUpstreamTaskCount = count($upstreamTaskList);

            /**
             * 外部任务分两种
             * 发送给乙方
             * 甲方的任务
             */
            $sendToOutsideTaskList = [];
            $fromPartyATaskList = [];
            // 判断上游任务是不是在外部制作
            foreach ($upstreamTaskList as $upstreamTaskItem) {
                /**
                 * 上游任务不是本租户任务
                 * 上游任务已被外包
                 */
                if ($upstreamTaskItem['tenant_id'] !== $task['tenant_id']) {
                    $fromPartyATaskList[] = $upstreamTaskItem;
                } elseif ($upstreamTaskItem['executor_tenant_id'] !== 0 && $upstreamTaskItem['executor_tenant_id'] !== $upstreamTaskItem['tenant_id']) {
                    $sendToOutsideTaskList[] = $upstreamTaskItem;
                } else {
                    $insideUpstreamTaskList[] = $upstreamTaskItem;
                }
            }
            $needDownloadFromPartyA = [];
            if (!empty($fromPartyATaskList)) {
                // 把甲方任务替换为 订单发送给乙方的任务
                $fromPartyATaskIdList = array_column($fromPartyATaskList, 'id');
                $sendToCurrentTenantTaskList = model(OrderModel::class)
                    ->join('order_task_list otl on `order`.id = otl.order_id')
                    ->where(['`order`.to_tenant_id' => $task['tenant_id'], 'otl.task_id' => ['IN', implode(',', $fromPartyATaskIdList)]])
                    ->where(['otl.status' => OrderTaskListModel::STATUS_DEFAULT])
                    ->field('otl.task_id,otl.real_task_id')
                    ->select();
                if (!empty($sendToCurrentTenantTaskList)) {
                    $taskIdList = array_column($sendToCurrentTenantTaskList, 'real_task_id');
                    $taskMap = array_column($sendToCurrentTenantTaskList, 'real_task_id', 'task_id');
                    $insideTaskList = model(TaskModel::class)->where(['id' => ['IN', implode(',', $taskIdList)]])->select();
                    if (!empty($insideTaskList)) {
                        $insideTaskList = array_column($insideTaskList, null, 'id');
                        foreach ($fromPartyATaskList as $upstreamTask) {
                            if (isset($taskMap[$upstreamTask['id']])) {
                                $insideUpstreamTaskList[] = $insideTaskList[$taskMap[$upstreamTask['id']]];
                            } else {
                                $needDownloadFromPartyA[] = $upstreamTask;
                            }
                        }
                    }
                } else {
                    $needDownloadFromPartyA = $fromPartyATaskList;
                }
            }
            $needDownloadFromPartyB = [];
            if (!empty($sendToOutsideTaskList)) {
                $sendToOtherTenantTaskList = model(OrderModel::class)
                    ->join('order_task_list otl on `order`.id = otl.order_id')
                    ->where(['`order`.from_tenant_id' => $task['tenant_id'], 'otl.task_id' => ['IN', implode(',', array_column($sendToOutsideTaskList, 'id'))]])
                    ->where(['otl.status' => OrderTaskListModel::STATUS_DEFAULT])
                    ->field('otl.task_id,otl.real_task_id')
                    ->select();
                if (!empty($sendToOtherTenantTaskList)) {
                    $taskIdList = array_column($sendToOtherTenantTaskList, 'real_task_id');
                    $taskMap = array_column($sendToOtherTenantTaskList, 'real_task_id', 'task_id');
                    $outsideTaskList = model(TaskModel::class)->where(['id' => ['IN', implode(',', $taskIdList)]])->select();
                    if (!empty($outsideTaskList)) {
                        $outsideTaskList = array_column($outsideTaskList, null, 'id');
                        foreach ($sendToOutsideTaskList as $upstreamTask) {
                            if (isset($taskMap[$upstreamTask['id']]) && isset($outsideTaskList[$taskMap[$upstreamTask['id']]])) {
                                $needDownloadFromPartyB[] = $outsideTaskList[$taskMap[$upstreamTask['id']]];
                            } else {
                                // todo 如果外包出去的任务订单丢失 怎么处理
                            }
                        }
                    }
                }
            }
            $needDownloadTaskList = array_merge($needDownloadFromPartyA, $needDownloadFromPartyB);
            //$needDownloadCount = count($needDownloadTaskList);
            if (!empty($needDownloadTaskList)) {
                $downloadRecordsMaxVersionIdList = model(OrderTaskUpstreamVersionModel::class)
                    ->where(['to_tenant_id' => $task['tenant_id'], 'task_id' => ['IN', implode(',', array_column($needDownloadTaskList, 'id'))]])
                    ->group('task_id')
                    ->field('max(version_id) as max_version_id')
                    ->select();
                if (!empty($downloadRecordsMaxVersionIdList)) {
                    $downloadRecords = model(OrderTaskUpstreamVersionModel::class)
                        ->where(['to_tenant_id' => $task['tenant_id'], 'version_id' => ['IN', implode(',', array_column($downloadRecordsMaxVersionIdList, 'max_version_id'))]])
                        ->select();
                    $downloadRecordsDownloaded = array_filter($downloadRecords, function ($item) {
                        return $item['is_download'] === 'yes';
                    });
                    $downloadRecordsDownloadedTaskIdList = array_column($downloadRecordsDownloaded, 'task_id');
                    $needDownloadTaskList = array_filter($needDownloadTaskList, function ($i) use ($downloadRecordsDownloadedTaskIdList) {
                        return !in_array($i['id'], $downloadRecordsDownloadedTaskIdList);
                    });
                    // 减掉最新版本已经下载的记录
                    //$needDownloadCount = $needDownloadCount - count($downloadRecordsDownloaded);
                }
                foreach ($needDownloadTaskList as $needDownloadTask) {
                    if (isset($relevanceStepMap[$needDownloadTask['step_id']]) && $relevanceStepMap[$needDownloadTask['step_id']] === 'yes') {
                        $needDownloadRelevantCount += 1;
                    } else {
                        $needDownloadUnRelevantCount += 1;
                    }
                }
            }

            $doneStatus = StatusService::getInstance()->getTaskDoneStatus();
            foreach ($insideUpstreamTaskList as $taskItem) {
                $taskItem = array_merge($taskItem, json_decode($taskItem['json'] ?? '{}', true));
                if (!isset($taskItem['task_status']) || $taskItem['task_status'] != $doneStatus['id']) {
                    if (isset($relevanceStepMap[$taskItem['step_id']]) && $relevanceStepMap[$taskItem['step_id']] === 'yes') {
                        $relevanceUndoneCount += 1;
                    } else {
                        $unRelevanceUndoneCount += 1;
                    }
                }
            }
        }

        $canAssemble = $unRelevanceUndoneCount === 0 && $needDownloadUnRelevantCount === 0;
        $res = [];
        $res['flag'] = $canAssemble;
        $res['relevant_need_download_count'] = $needDownloadRelevantCount;
        $res['unrelevant_need_download_count'] = $needDownloadUnRelevantCount;
        $res['relevant_undone_count'] = $relevanceUndoneCount; // 关联
        $res['unrelevant_undone_count'] = $unRelevanceUndoneCount; // 上游
        $res['total_upstream_task_count'] = $totalUpstreamTaskCount;
        return $res;
    }

    /**
     * 查询衍生任务数据
     * @param array $task
     * @param array $fields
     * @param callable $itemCallback
     * @return array
     * @throws Exception
     */
    public function getUpstreamTodoTaskList(array $task, array $fields, callable $itemCallback)
    {
        $res = [];
        // 贴图材质工序 需要显示关联衍生
        $entityModuleCode = module_by_id($task['entity_module_id'])['code'];
        $entityTodoTaskIdStr = model(EntityModel::class)
            ->alias($entityModuleCode)
            ->where(['id' => $task['entity_id']])
            ->field(transform_custom_field($entityModuleCode . '_task', $entityModuleCode) . ' as ' . $entityModuleCode . '_task')
            ->value($entityModuleCode . '_task');
        $entityTodoTaskIdList = array_filter(explode(',', $entityTodoTaskIdStr));
        if (empty($entityTodoTaskIdList)) {
            return $res;
        }
        $entityTodoTaskListFilter = ['task.id' => ['IN', $entityTodoTaskIdList]];
        $entityTodoTaskList = $this->taskModel
            ->join('entity ON entity.id = task.entity_id')
            ->join('status ON status.id = JSON_UNQUOTE(JSON_EXTRACT(task.json,\'$.task_status\'))', 'LEFT')
            ->join('step ON task.step_id = step.id', 'LEFT')
            ->where($entityTodoTaskListFilter)
            ->field(build_complex_query_fields($fields, '__'))
            ->select();
        $callback = function ($item) use ($itemCallback) {
            $res = $itemCallback($item);
            if (!empty($res['status']['code']) && $res['status']['code'] === 'not_started') {
                $res['status']['name'] = '未完成';
            }
            return $res;
        };
        return array_map($callback, $entityTodoTaskList);
    }

    /**
     * 查询衍生任务数据
     * @param array $entityIdList
     * @param array $fields
     * @param callable $itemCallback
     * @return array
     * @throws Exception
     */
    public function batchGetUpstreamTodoTaskList(array $entityIdList, array $fields, callable $itemCallback)
    {
        $res = [];
        $entityList = model(EntityModel::class)
            ->where(['id' => ['IN', $entityIdList]])
            ->field('id,module_id,json')
            ->select();
        $taskEntityMap = [];
        $taskIdList = [];
        foreach ($entityList as $entity) {
            $entityModuleCode = module_by_id($entity['module_id'])['code'];
            $taskField = $entityModuleCode . '_task';
            $currentTaskIdList = array_filter(explode(',', json_decode($entity['json'], true)[$taskField] ?? ''));
            foreach ($currentTaskIdList as $currentTaskId) {
                $taskEntityMap[$currentTaskId] = $entity['id'];
            }
            $taskIdList = array_merge($taskIdList, $currentTaskIdList);
        }
        // 贴图材质工序 需要显示关联衍生
        if (empty($taskIdList)) {
            return $res;
        }
        $entityTodoTaskListFilter = ['task.id' => ['IN', $taskIdList]];
        $entityTodoTaskList = $this->taskModel
            ->join('entity ON entity.id = task.entity_id')
            ->join('status ON status.id = JSON_UNQUOTE(JSON_EXTRACT(task.json,\'$.task_status\'))', 'LEFT')
            ->join('step ON task.step_id = step.id', 'LEFT')
            ->where($entityTodoTaskListFilter)
            ->field(build_complex_query_fields($fields, '__'))
            ->select();
        $callback = function ($item) use ($itemCallback) {
            $res = $itemCallback($item);
            if (!empty($res['status']['code']) && $res['status']['code'] === 'not_started') {
                $res['status']['name'] = '未完成';
            }
            return $res;
        };
        $res = array_map($callback, $entityTodoTaskList);
        foreach ($res as &$resItem) {
            $resItem['entity_id'] = $taskEntityMap[$resItem['task']['id']] ?? 0;
        }
        return array_group_by($res, 'entity_id');
    }

    /**
     * 查询衍生任务数据
     * @param int $entityId
     * @param array $entityIdList
     * @param array $fields
     * @param callable $itemCallback
     * @return array
     * @throws Exception
     */
    public function batchGetRelatedUpstreamTodoTaskList(int $entityId, array $entityIdList, array $fields, callable $itemCallback)
    {
        /**
         * 贴图对应的是概念的实体id
         * 当前实体关联的是资产id
         */
        $res = [];
        $currentEntity = model(EntityModel::class)->where(['id' => $entityId])->field('id,module_id,json')->find();
        if (empty($currentEntity)) {
            throw new LogicException("entity not found", ErrorCode::ENTITY_NOT_FOUND);
        }
        $entityModuleCode = module_by_id($currentEntity['module_id'])['code'];
        $taskField = $entityModuleCode . '_task';
        $entityJsonFields = json_decode($currentEntity['json'], true);
        // 当前实体关联的贴图列表
        $currentTodoTaskIdList = array_filter(explode(',', $entityJsonFields[$taskField] ?? ''));
        $upstreamDesignIdField = 'asset_design';
        $upstreamDesignIdList = model(EntityModel::class)
            ->alias('asset')
            ->where(['id' => ['IN', $entityIdList]])
            ->field('id,' . transform_custom_field($upstreamDesignIdField, 'asset') . ' AS ' . $upstreamDesignIdField)
            ->select();
        $upstreamDesignIdMap = array_column($upstreamDesignIdList, 'id', $upstreamDesignIdField);
        $upstreamDesignIdList = array_column($upstreamDesignIdList, $upstreamDesignIdField);
        if (empty($currentTodoTaskIdList) || empty($upstreamDesignIdList)) {
            return $res;
        }
        // 贴图材质工序 需要显示关联衍生
        $entityTodoTaskListFilter = [
            'entity.id' => ['IN', $upstreamDesignIdList],
            'task.id' => ['IN', $currentTodoTaskIdList],
        ];
        $entityTodoTaskList = $this->taskModel
            ->join('entity ON entity.id = task.entity_id')
            ->join('status ON status.id = JSON_UNQUOTE(JSON_EXTRACT(task.json,\'$.task_status\'))', 'LEFT')
            ->join('step ON task.step_id = step.id', 'LEFT')
            ->where($entityTodoTaskListFilter)
            ->field(build_complex_query_fields($fields, '__'))
            ->select();
        $callback = function ($item) use ($itemCallback) {
            $res = $itemCallback($item);
            if (!empty($res['status']['code']) && $res['status']['code'] === 'not_started') {
                $res['status']['name'] = '未完成';
            }
            return $res;
        };
        $res = array_map($callback, $entityTodoTaskList);
        foreach ($res as &$item) {
            $item['relate_asset_id'] = $upstreamDesignIdMap[$item['entity']['id']] ?? 0;
        }
        return array_column($res, null, 'relate_asset_id');
    }

    /**
     * 获取上游实体任务
     * @param $taskId
     * @return array
     */
    public function getAllUpstreamEntityTask($taskId): array
    {
        $task = model(TaskModel::class)->field("entity_id,step_id,entity_module_id,project_id,JSON_UNQUOTE(JSON_EXTRACT(json,'$.step_workflow_id')) as step_workflow_id")->find($taskId);
        if (empty($task)) {
            return [];
        }
        $project = model(ProjectModel::class)->where(['id' => $task["project_id"]])->field("project_template_id")->find();
        $upstreamProcess = StepService::getInstance()->getUpstreamProcess($project["project_template_id"] ?? 0, $task['project_id'] ?? 0, $task['step_workflow_id'] ?? 0, $task["step_id"] ?? 0, false, false);
        if (empty($upstreamProcess["step_list"])) {
            return [];
        }
        $moduleProcess = $upstreamProcess["module_process"];
        $entityDataIds = [];
        $entityList = model(EntityModel::class)->where(["id" => $task["entity_id"]])->field("id,module_id,json")->select();
        EntityUpstreamService::getInstance()->downGetUpstreamEntity($entityList, $moduleProcess, $entityDataIds);
        $taskList = model(TaskModel::class)
            ->where(["entity_id" => ["IN", $entityDataIds], "step_id" => ["IN", $upstreamProcess["step_list"]], "step_type" => "step"])
            ->field("id,step_category_id,name,json->>'$.task_status' as task_status")
            ->select();
        $res = [];
        $closedStatusId = StatusService::getInstance()->getTaskDefaultClosedStatus()['id'];
        foreach ($taskList as $taskItem) {
            if ($taskItem['task_status'] == $closedStatusId) {
                continue;
            }
            $res[] = $taskItem;
        }
        return $res;
    }

    /**
     * 查询上游实体列表 通过关联关系获取
     * @param $entityIds
     * @return array
     */
    public function batchGetUpstreamEntityList($entityIds): array
    {
        $relatedEntities = [];
        $entityList = model(EntityModel::class)->where(["id" => ["IN", $entityIds]])->select();
        // 实体不存在那么 返回空数组
        if (empty($entityList)) {
            return $relatedEntities;
        }
        $entityModuleIds = [];
        $projectId = 0;
        foreach ($entityList as $entity) {
            $entityModuleIds[] = $entity['module_id'];
            if (empty($projectId)) {
                $projectId = $entity["project_id"];
            }
            $relatedEntities[$entity['id']] = [$entity['id']];
            switch ($entity['module_id']) {
                case Module::$moduleDictData['module_index_by_code']['shot']['id']:
                    /**
                     * 序列也是镜头的关联
                     */
                    if ($entity['entity_id'] > 0) {
                        $relatedEntities[$entity['id']][] = $entity['entity_id'];
                    }
                    break;
                default:
            }
        }
        $entityModuleIds = array_unique($entityModuleIds);
        /**
         * 查询实体的分类id
         */
        $entityStepCategory = model(StepCategoryModel::class)->where(['entity_id' => ["IN", $entityModuleIds]])->select();
        $stepCategoryEntityModuleMap = [];
        $entityStepCategoryIds = [];
        foreach ($entityStepCategory as $entityStepCategoryItem) {
            $stepCategoryEntityModuleMap[$entityStepCategoryItem["id"]] = $entityStepCategoryItem['entity_id'];
            $entityStepCategoryIds[] = $entityStepCategoryItem["id"];
        }
        $projectTemplate = model(ProjectTemplateModel::class)
            ->join("project ON project.project_template_id = project_template.id")
            ->where([
                'project.id' => $projectId,
            ])
            ->field("project_template.step_category_dependency")
            ->find();
        if (empty($projectTemplate)) {
            return $relatedEntities;
        }
        $stepCategoryDependency = json_decode($projectTemplate['step_category_dependency'], true);
        /**
         * 没有 一级分类关系配置 直接返回true
         */
        if (empty($stepCategoryDependency['edges'])) {
            return $relatedEntities;
        }
        $sources = [];
        $sourcesEntityModuleMap = [];
        foreach ($stepCategoryDependency['edges'] as $edge) {
            if (in_array($edge['target'], $entityStepCategoryIds)) {
                if (!in_array($edge['source'], $sources)) {
                    $sources[] = $edge['source'];
                }
                if (!isset($sourcesEntityModuleMap[$stepCategoryEntityModuleMap[$edge['target']]])) {
                    $sourcesEntityModuleMap[$stepCategoryEntityModuleMap[$edge['target']]] = [$edge['source']];
                } elseif (!in_array($edge['source'], $sourcesEntityModuleMap[$stepCategoryEntityModuleMap[$edge['target']]])) {
                    $sourcesEntityModuleMap[$stepCategoryEntityModuleMap[$edge['target']]][] = $edge['source'];
                }
            }
        }
        if (!empty($sources)) {
            /**
             * 上游
             *
             * 当前实体关联的数据
             *
             * current_module_code_relation_source_code
             *
             * etc: level_asset
             *
             */
            $sourceStepCategories = model(StepCategoryModel::class)
                ->where(['id' => ['IN', implode(',', $sources)]])
                ->select();
            $sourceStepCategories = array_column($sourceStepCategories, null, "id");
            foreach ($entityList as $entityItem) {
                $moduleCode = module_by_id($entityItem['module_id'])['code'];
                $entityItem['json'] = json_decode($entityItem['json'], true);
                foreach ($sourcesEntityModuleMap[$entityItem['module_id']] as $sourcesEntityModuleStepCategoryId) {
                    $sourceStepCategoryCode = $sourceStepCategories[$sourcesEntityModuleStepCategoryId]["code"];
                    $relationEntityStr = $entityItem['json']["{$moduleCode}_{$sourceStepCategoryCode}"] ?? "";
                    $tmpRelatedEntities = explode(',', $relationEntityStr);
                    $tmpRelatedEntities = array_filter($tmpRelatedEntities, function ($item) {
                        return intval($item) > 0;
                    });
                    if (empty($tmpRelatedEntities)) {
                        continue;
                    }
                    $relatedEntities[$entityItem['id']] = array_merge($relatedEntities[$entityItem['id']], $tmpRelatedEntities);
                }
            }
        }
        return $relatedEntities;
    }

    /**
     * 获得上游任务列表
     * @param $taskIds
     * @param array $upTaskFields
     * @return array
     * @throws \Exception
     */
    public function batchGetUpstreamTaskList($taskIds, $upTaskFields = [])
    {
        $task = $this->taskModel->where(["id" => ["IN", $taskIds]])->select();
        // 任务关系转换,子任务,转换成父任务
        $dismantleTaskMap = DismantleTaskService::getInstance()->batchDismantleTaskTransformationMap($task);
        foreach ($task as $index => $taskItem) {
            if (isset($dismantleTaskMap[$taskItem["id"]])) {
                $tasks[$index] = $dismantleTaskMap[$taskItem["id"]];
            }
        }
        if (empty($task)) {
            throw new LogicException("can`t found task", ErrorCode::TASK_NOT_FOUND);
        }
        $projectId = $task[0]['project_id'];
        $project = model(ProjectModel::class)->where(['id' => $projectId])->field('type')->find();
        $relationMap = [];
        if ($project['type'] === 'outsource') {
            $orderService = OrderService::getInstance();
            $taskIdList = array_column($task, 'id');
            $relationMap = $orderService->getSourceTaskListByTaskIdList($taskIdList);
        }
        //替换
        $stepIds = [];
        $entityIds = [];
        $stepEntityMap = [];
        $taskListMap = [];
        foreach ($task as $taskIndex => $taskItem) {
            if (isset($relationMap[$taskItem['id']])) {
                $taskItem = $relationMap[$taskItem['id']];
                $task[$taskIndex] = $taskItem;
            }
            $stepIds[$taskItem["step_id"]] = $taskItem["step_id"];
            $entityIds[$taskItem["entity_id"]] = $taskItem["entity_id"];
            if (!isset($stepEntityMap[$taskItem["step_id"]])) {
                $stepEntityMap[$taskItem["step_id"]] = [$taskItem["entity_id"]];
            } elseif (!in_array($taskItem["entity_id"], $stepEntityMap[$taskItem["step_id"]])) {
                $stepEntityMap[$taskItem["step_id"]][] = $taskItem["entity_id"];
            }
            $taskListMap[$taskItem['id']] = $taskItem;
        }
        $stepIds = array_values($stepIds);
        $entityIds = array_values($entityIds);
        $entityMapList = $this->batchGetUpstreamEntityList($entityIds);
        $taskId = $task[0]['id'];
        $result = [];
        if (!empty($entityMapList)) {
            $projectTemplateId = TaskService::getInstance()->getTaskProjectTemplateId($taskId);
            $stepService = StepService::getInstance();
            $upstreamSteps = $stepService->batchGetStepUpstreamMap($stepIds, $projectTemplateId);
            //条件组装
            $taskFilter = [];
            foreach ($stepEntityMap as $stepId => $entityIdList) {
                if (!isset($upstreamSteps[$stepId])) {
                    continue;
                }
                $currentStepEntityIdList = [];
                foreach ($entityIdList as $entityIdListItem) {
                    if (isset($entityMapList[$entityIdListItem])) {
                        //组合当前工序的所有上游实体
                        $currentStepEntityIdList = array_merge($currentStepEntityIdList, $entityMapList[$entityIdListItem]);
                    }
                }
                if (empty($currentStepEntityIdList)) {
                    continue;
                }
                $taskFilter[] = [
                    'entity_id' => ['IN', $currentStepEntityIdList],
                    'step_id' => ["IN", $upstreamSteps[$stepId]]
                ];
            }
            if (!empty($taskFilter)) {
                $taskFilter["_logic"] = "OR";
                //查询出所有上游
                $taskListFields = ["step_id", "entity_id"];
                $taskListFields = array_merge($upTaskFields, $taskListFields);
                $taskList = $this->taskModel->where($taskFilter)->field($taskListFields)->select();
                $taskMap = [];
                foreach ($taskList as $taskListItem) {
                    $taskMap[$taskListItem['step_id']][$taskListItem['entity_id']] = $taskListItem;
                }
                //回填组装
                foreach ($taskIds as $taskIdItem) {
                    //先要换成父任务id
                    $currentTaskId = $taskIdItem;
                    if (isset($dismantleTaskMap[$currentTaskId])) {
                        $currentTaskId = $dismantleTaskMap[$currentTaskId]["id"];
                    }
                    //在换成外包任务id
                    if (isset($relationMap[$currentTaskId])) {
                        $currentTaskId = $relationMap[$currentTaskId]["id"];
                    }
                    $result[$currentTaskId] = [];
                    //通过任务拿到step_id , entity_id
                    //再通过step_id拿到上游的step_id, 以及通过entity_id拿到上游的entity_id
                    // 通过上游 step_id与entity_id比对获取任务
                    if (!isset($taskListMap[$currentTaskId])) {
                        continue;
                    }
                    $currentStepId = $taskListMap[$currentTaskId]["step_id"];
                    $currentEntityId = $taskListMap[$currentTaskId]["entity_id"];
                    if (!isset($upstreamSteps[$currentStepId]) || !isset($entityMapList[$currentEntityId])) {
                        continue;
                    }
                    foreach ($upstreamSteps[$currentStepId] as $currentStepIdItem) {
                        foreach ($entityMapList[$currentEntityId] as $entityMapListItem) {
                            if (!isset($taskMap[$currentStepIdItem][$entityMapListItem])) {
                                continue;
                            }
                            if (!in_array($taskMap[$currentStepIdItem][$entityMapListItem], $result[$currentTaskId])) {
                                $result[$currentTaskId][] = $taskMap[$currentStepIdItem][$entityMapListItem];
                            }
                        }
                    }
                }
            }
        }
        return $result;
    }

    /**
     * 查询上游实体列表 通过关联关系获取
     * @param $entityIdList
     * @return array
     */
    public function getUpstreamEntityListBatch($entityIdList): array
    {
        $entityList = model(EntityModel::class)->where(['id' => ['IN', $entityIdList]])->select();
        // 实体不存在那么 返回空数组
        if (empty($entityList)) {
            return [];
        }
        $projectTemplate = model(ProjectTemplateModel::class)
            ->join("project ON project.project_template_id = project_template.id")
            ->where([
                'project.id' => $entityList[0]['project_id'],
            ])
            ->field("project_template.step_category_dependency")
            ->cache(C('database.default_query_cache_time'))
            ->find();
        $edges = [];
        if (!empty($projectTemplate)) {
            $stepCategoryDependency = json_decode($projectTemplate['step_category_dependency'], true);
            $edges = $stepCategoryDependency['edges'] ?? [];
        }
        $stepCategoryList = StepCategoryService::getInstance()->getList([], '*');
        $entityStepCategoryList = array_column(array_filter($stepCategoryList, function ($i) {
            return $i['parent_id'] == 0;
        }), null, 'entity_id');
        $stepCategoryMap = array_column($stepCategoryList, null, 'id');
        $edgesGrouped = [];
        foreach ($edges as $sourceStepCategory) {
            if (isset($stepCategoryMap[$sourceStepCategory['source']])) {
                $edgesGrouped[$sourceStepCategory['target']][] = $stepCategoryMap[$sourceStepCategory['source']];
            }
        }
        foreach ($entityList as &$entity) {
            $entityModule = module_by_id($entity['module_id']);
            $entity['upstream_entity_id_list'] = [];
            if ($entityModule['code'] == 'shot' && $entity['entity_id'] > 0) {
                $entity['upstream_entity_id_list'][] = $entity['entity_id'];
            }
            // 实体模块找不到分类
            if (empty($entityStepCategoryList[$entity['module_id']])) {
                continue;
            }
            $entity['json'] = json_decode($entity['json'], true);
            $entityStepCategory = $entityStepCategoryList[$entity['module_id']];
            // 项目模板没有配置上游relation
            if (empty($edgesGrouped[$entityStepCategory['id']])) {
                continue;
            }
            foreach ($edgesGrouped[$entityStepCategory['id']] as $sourceStepCategory) {
                $relateField = "{$entityModule['code']}_{$sourceStepCategory['code']}";
                if (empty($entity['json'][$relateField])) {
                    continue;
                }
                foreach (explode(',', $entity['json'][$relateField]) as $relateId) {
                    $relateId = intval($relateId);
                    if ($relateId <= 0) {
                        continue;
                    }
                    $entity['upstream_entity_id_list'][] = $relateId;
                }
            }
        }
        return array_column($entityList, null, 'id');
    }

    /**
     * 获得上游任务列表
     * @param array $taskIdList
     * @param bool $onlyRelativeNo 只要非关联性的任务
     * @param bool $closeShow 是否显示已取消任务
     * @return array
     */
    public function getUpstreamTaskListBatch(array $taskIdList, bool $onlyRelativeNo = false, bool $closeShow = false): array
    {
        $taskList = $this->taskModel->where(['id' => ['IN', $taskIdList]])->select();
        // 任务关系转换,子任务,转换成父任务
        $taskList = DismantleTaskService::getInstance()->dismantleTaskTransformationBatch($taskList);
        if (empty($taskList)) {
            throw new LogicException("can`t found task", ErrorCode::TASK_NOT_FOUND);
        }
        $project = model(ProjectModel::class)->where(['id' => $taskList[0]['project_id']])->field('type,project_template_id')->cache(C('database.default_query_cache_time'))->find();
        if ($project['type'] === 'outsource') {
            $orderService = OrderService::getInstance();
            $taskList = $orderService->getSourceTaskListByTaskList($taskList);
        }
        $returnData = [];
        $entityIdList = [];
        $stepIdList = [];
        $newStepWorkflowTaskList = [];
        $oldStepWorkflowTaskList = [];
        foreach ($taskList as &$task) {
            $taskJsonData = json_decode($task['json'], true);
            $entityIdList[$task['entity_id']] = $task['entity_id'];
            $stepIdList[$task['step_id']] = $task['step_id'];
            $task['upstream_entity_id_list'] = [];
            $task['upstream_step_id_list'] = [];
            $task['upstream_task_list'] = [];
            $task['step_workflow_id'] = $taskJsonData['step_workflow_id'] ?? 0;
            if (!empty($task['step_workflow_id'])) {
                $newStepWorkflowTaskList[] = $task;
            }
            if (empty($task['step_workflow_id'])) {
                $oldStepWorkflowTaskList[] = $task;
            }
        }
        // 新工序流
        if (!empty($newStepWorkflowTaskList)) {
            foreach ($newStepWorkflowTaskList as $newStepWorkflowTaskItem) {
                $upstreamList = TaskUpstreamService::getInstance()->getStepUpDownstreamTaskList($newStepWorkflowTaskItem['id']);
                foreach ($upstreamList as $upstreamItem) {
                    if ($upstreamItem['upstream_task_info']['step_type'] != TaskModel::STEP_TYPE_STEP) {
                        continue;
                    }
                    $newStepWorkflowTaskItem['upstream_task_list'][] = $upstreamItem['upstream_task_info'];
                    $returnData[$newStepWorkflowTaskItem['id']] = $newStepWorkflowTaskItem;
                }
            }
        }
        // 旧工序流
        if (!empty($oldStepWorkflowTaskList)) {
            $oldStepWorkflowUpstreamTaskList = $this->getOldStepWorkflowUpstreamTaskList($oldStepWorkflowTaskList, $entityIdList, $project, $stepIdList, $onlyRelativeNo);
            foreach ($oldStepWorkflowUpstreamTaskList as $oldStepWorkflowUpstreamTaskItem) {
                $returnData[$oldStepWorkflowUpstreamTaskItem['id']] = $oldStepWorkflowUpstreamTaskItem;
            }
        }
        return array_map(function ($tmp) use ($closeShow) {
            $upstreamTaskList = $tmp['upstream_task_list'] ?? [];
            if (!$closeShow) {
                $closedStatus = StatusService::getInstance()->getOne(['code' => 'closed'], '*');
                $closedStatusId = $closedStatus['id'];
                $upstreamTaskList = array_filter($tmp['upstream_task_list'], function ($task) use ($closedStatusId) {
                    $jsonFields = json_decode($task['json'], true);
                    return $jsonFields['task_status'] != $closedStatusId;
                });
                $upstreamTaskList = array_values($upstreamTaskList);
            }
            $tmp['upstream_task_list'] = $upstreamTaskList;
            return $tmp;
        }, $returnData);
    }

    /**
     * 旧工序流上游获取
     * @param $oldStepWorkflowTaskList
     * @param $entityIdList
     * @param $project
     * @param $stepIdList
     * @param $onlyRelativeNo
     * @return mixed
     */
    public function getOldStepWorkflowUpstreamTaskList($oldStepWorkflowTaskList, $entityIdList, $project, $stepIdList, $onlyRelativeNo)
    {
        $entityList = $this->getUpstreamEntityListBatch($entityIdList);
        if (empty($entityList)) {
            return $oldStepWorkflowTaskList;
        }
        $stepService = StepService::getInstance();
        $upstreamSteps = $stepService->getStepsUpstreams($project['project_template_id'], $stepIdList, $onlyRelativeNo);
        if (empty($upstreamSteps)) {
            return $oldStepWorkflowTaskList;
        }
        $resFilter = [];
        foreach ($oldStepWorkflowTaskList as &$task) {
            $task['upstream_entity_id_list'] = [];
            $task['upstream_step_id_list'] = [];
            if (empty($entityList[$task['entity_id']])) {
                continue;
            }
            $entity = $entityList[$task['entity_id']];
            $entityUpstreamEntityIdList = $entity['upstream_entity_id_list'];
            $entityUpstreamEntityIdList[] = $entity['id'];
            if (empty($upstreamSteps[$task['step_id']])) {
                continue;
            }
            $taskStepUpstream = $upstreamSteps[$task['step_id']];
            $task['upstream_entity_id_list'] = $entityUpstreamEntityIdList;
            $task['upstream_step_id_list'] = array_column($taskStepUpstream, 'step_id');
            $resFilter[] = [
                'task.entity_id' => ['IN', implode(',', $task['upstream_entity_id_list'])],
                'task.step_id' => ['IN', implode(',', $task['upstream_step_id_list'])],
            ];
        }
        if (count($resFilter) > 1) {
            $resFilter["_logic"] = 'or';
        } else {
            $resFilter = array_shift($resFilter);
        }
        $upstreamTaskList = model(TaskModel::class)
            ->where(['task.step_type' => TaskModel::STEP_TYPE_STEP])
            ->where([$resFilter])
            ->field("task.*,concat(task.entity_id,'#',task.step_id) uk")
            ->select();
        $upstreamTaskList = array_column($upstreamTaskList, null, 'uk');
        unset($task);
        foreach ($oldStepWorkflowTaskList as &$task) {
            $task['upstream_task_list'] = [];
            foreach ($task['upstream_entity_id_list'] as $entityId) {
                foreach ($task['upstream_step_id_list'] as $stepId) {
                    $uk = $entityId . '#' . $stepId;
                    if (!isset($upstreamTaskList[$uk])) {
                        continue;
                    }
                    $task['upstream_task_list'][] = $upstreamTaskList[$uk];
                }
            }
        }
        return $oldStepWorkflowTaskList;
    }


    /**
     * 同步任务上下游关系
     * @param int $taskId 任务ID
     * @return int
     */
    public function syncTaskUpstream(int $taskId)
    {
        if (empty($taskId)) {
            return 0;
        }
        //获取项目ID
        $taskInfo = model(TaskModel::class)->field('id,project_id')->where(['id' => $taskId])->find();
        if (empty($taskInfo)) {
            return 0;
        }
        //判断--是否已有关系记录
        $oldIdList = model(TaskRelationModel::class)
            ->setSuffix(sprintf('_project_%d', $taskInfo['project_id']))
            ->field('target_task_id')
            ->where(['source_task_id' => $taskId, 'relation_type' => ['IN', TaskRelationModel::RELATION_TYPE]])
            ->column('target_task_id');

        $upstreamList = TaskUpstreamService::getInstance()->getStepUpDownstreamTaskList($taskId, 'upstream');
        $newIdList = array_column($upstreamList, 'upstream_task_id');

        //有记录--修改关联关系表
        $upstreamList = array_column($upstreamList, null, 'upstream_task_id');
        $this->modifyTaskUpstream($taskInfo, $newIdList, $oldIdList, $upstreamList);
        return 1;
    }


    /**
     * 修改任务上游关系
     * @param array $taskInfo 任务信息
     * @param array $newIdList 新增的上游任务IDs
     * @param array $oldIdList 已有的上游任务IDs
     * @return void
     */
    private function modifyTaskUpstream(array $taskInfo, array $newIdList, array $oldIdList, $upstreamList)
    {
        //已有记录
        $needRemoveList = array_diff($oldIdList, $newIdList);
        $needAddList = array_diff($newIdList, $oldIdList);
        //删除记录
        $this->delTaskUpstream($taskInfo, $needRemoveList);
        //新增记录
        $this->addTaskUpstream($taskInfo, $needAddList, $upstreamList);
    }


    /**
     * 增加任务上游关系
     * @param array $taskInfo 任务信息
     * @param array $targetTaskList 目标任务ID
     * @param array $newList
     * @return int
     */
    public function addTaskUpstream(array $taskInfo, array $targetTaskList, array $newList)
    {
        if (empty($targetTaskList)) {
            return 0;
        }
        try {
            $taskRelationItem = [];
            foreach ($targetTaskList as $val) {
                $taskRelationItem[] = [
                    'target_task_id' => $val,
                    'source_task_id' => $taskInfo['id'],
                    'project_id' => $taskInfo['project_id'],
                    'source_step_category_id' => $newList[$val]['source_step_category_id'] ?? 0,
                    'target_step_category_id' => $newList[$val]['target_step_category_id'] ?? 0,
                    'relation' => $newList[$val]['relation'] ?? '',
                    'uuid' => create_uuid(),
                    'relation_type' => $newList[$val]['relation_type'] ?? ''
                ];
            }
            model(TaskRelationModel::class)->setSuffix(sprintf('_project_%d', $taskInfo['project_id']))->addAll($taskRelationItem);
        } catch (\Exception $e) {
            trace('增加任务上游关系失败' . PHP_EOL . format_exception_info($e), 'ERR');
            return 0;
        }
        return 1;
    }

    /**
     * 删除任务上游关系
     * @param array $taskInfo 任务ID
     * @param array $targetTaskIds 目标任务Ids
     * @return void
     */
    private function delTaskUpstream(array $taskInfo, array $targetTaskIds)
    {
        if (empty($targetTaskIds)) {
            return;
        }
        //删除条件
        $condition = [];
        $condition['relation_type'] = ['IN', TaskRelationModel::RELATION_TYPE];
        $condition['source_task_id'] = $taskInfo['id'];
        $condition['target_task_id'] = ['in', $targetTaskIds];

        try {
            //删除节点
            model(TaskRelationModel::class)->setSuffix(sprintf('_project_%d', $taskInfo['project_id']))->where($condition)->delete();
        } catch (\Exception $e) {
            trace('删除任务上游关系失败' . PHP_EOL . format_exception_info($e), 'ERR');
        }
    }

    /**
     *
     * 1.查出当前任务当前工序(step_id),实体(entity_id),集(episode_id)
     * 2. 拿到当前任务所在的工序和上游做匹配 step_id = target_id 查出上游工序
     * 3. 拿到当前任务所有的上游工序,根据关联类型分组
     * 4. 关联类型为实体:
     *                   找出当前实体下所有的工序任务，并且工序等于当前配置里的上游工序的工序任务
     *      关联类型为集：
     *                   找出当前集下所有的工序任务，并且工序等于配置里的上游工序的工序任务
     *      关联类型为关联:
     *                   找出当前实体关联的实体所有的工序任务，并且工序等于配置里的上游工序的工序任务
     * 查询工序流上游或下游任务id
     * @param $taskId
     * @param string $type (upstream:通过下游找上游,downstream 通过上游找下游,默认 upstream)
     * @return array
     */
    public function getStepUpDownstreamTaskList($taskId, string $type = 'upstream'): array
    {
        $stepUpDownStreamTaskList = [];
        if (empty($taskId)) {
            return $stepUpDownStreamTaskList;
        }

        $taskFields = [
            "id",
            "episode_id",
            "entity_id",
            "project_id",
            "step_id",
            "step_category_id",
            "JSON_UNQUOTE(JSON_EXTRACT(json,'$.step_workflow_id')) as step_workflow_id"
        ];
        $taskData = $this->taskModel->forceMasterDB()->field($taskFields)->where(['id' => $taskId])->find();
        if (empty($taskData)) {
            return $stepUpDownStreamTaskList;
        }

        $where = ['step_id' => $taskData['step_id'], 'step_workflow_id' => $taskData['step_workflow_id']];
        if ($type == 'downstream') {
            $where = ['upstream_step_id' => $taskData['step_id'], 'step_workflow_id' => $taskData['step_workflow_id']];
        }
        $stepUpstreamList = model(StepUpstreamModel::class)
            ->field('id,step_id,upstream_step_id,step_workflow_id,relation,relation_type,project_id')
            ->where($where)
            ->where(['project_id' => $taskData['project_id']])
            ->select();
        if (empty($stepUpstreamList)) {
            $stepUpstreamList = model(StepUpstreamModel::class)
                ->field('id,step_id,upstream_step_id,step_workflow_id,relation,relation_type,project_id')
                ->where($where)
                ->where(['project_id' => 0])
                ->select();
            if (empty($stepUpstreamList)) {
                return $stepUpDownStreamTaskList;
            }
        }

        $episodeUpstreamStepIdList = [];
        $entityUpstreamStepIdList = [];
        foreach ($stepUpstreamList as $stepUpstreamItem) {
            // 上游关联类型是集的
            if ($stepUpstreamItem['relation_type'] == 'episode') {
                $episodeUpstreamStepIdList[] = $stepUpstreamItem;
            }
            // 上游关联类型是实体和上游关联类型是"关联"的
            if (in_array($stepUpstreamItem['relation_type'], ['entity', 'relation'])) {
                $entityUpstreamStepIdList[] = $stepUpstreamItem;
            }
        }
        // 集
        if (!empty($episodeUpstreamStepIdList)) {
            $getEpisodeUpstreamStepTaskList = $this->getEpisodeUpstreamStepTaskList($episodeUpstreamStepIdList, $taskData['episode_id'], $taskData['project_id'], $taskData['step_category_id'], $type);
            $stepUpDownStreamTaskList = array_merge($stepUpDownStreamTaskList, $getEpisodeUpstreamStepTaskList);
        }
        // 实体
        if (!empty($entityUpstreamStepIdList)) {
            $getEntityUpstreamStepTaskList = $this->getEntityUpstreamStepTaskList($entityUpstreamStepIdList, $taskData['entity_id'], $taskData['project_id'], $taskData['step_category_id'], $type);
            $stepUpDownStreamTaskList = array_merge($stepUpDownStreamTaskList, $getEntityUpstreamStepTaskList);
        }
        return $stepUpDownStreamTaskList;
    }


    /**
     * 获取关联类似是关联实体的上游工序任务
     * @param $entityUpstreamStepIdList
     * @param $entityId
     * @param $projectId
     * @param $StepCategoryId
     * @param $type
     * @return array
     */
    public function getEntityUpstreamStepTaskList($entityUpstreamStepIdList, $entityId, $projectId, $StepCategoryId, $type): array
    {
        $entityIds[] = $entityId;
        $returnData = [];
        $entityUpstreamStepIds = [];
        $entityUpstreamStepIdMap = [];
        $upDownStreamIndex = 'upstream_step_id';
        if ($type == 'downstream') {
            $upDownStreamIndex = 'step_id';
        }
        foreach ($entityUpstreamStepIdList as $entityUpstreamStepItem) {
            $entityUpstreamStepKey = sprintf('step_id_%d', $entityUpstreamStepItem[$upDownStreamIndex]);
            $entityUpstreamStepIdMap[$entityUpstreamStepKey] = $entityUpstreamStepItem;
            $entityUpstreamStepIds[] = $entityUpstreamStepItem[$upDownStreamIndex];
        }
        // 关联实体
        $relationTaskList = $this->getRelationEntityIds($entityId, $type);
        if (!empty($relationTaskList)) {
            foreach ($relationTaskList as $relationEntityId) {
                $entityIds[] = $relationEntityId;
            }
        }
        $entityTaskList = $this->getEntityTaskIds($entityUpstreamStepIds, $entityIds, $projectId);
        if (empty($entityTaskList)) {
            return $returnData;
        }
        foreach ($entityTaskList as $entityTaskItem) {
            $entityUpstreamStepKey = sprintf('step_id_%d', $entityTaskItem['step_id']);
            if (empty($entityUpstreamStepIdMap[$entityUpstreamStepKey])) {
                continue;
            }
            $entityUpstreamStepIdMap[$entityUpstreamStepKey]['upstream_task_id'] = $entityTaskItem['id'];
            $entityUpstreamStepIdMap[$entityUpstreamStepKey]['upstream_task_info'] = $entityTaskItem;
            $entityUpstreamStepIdMap[$entityUpstreamStepKey]['downstream_task_id'] = $entityTaskItem['id'];
            $entityUpstreamStepIdMap[$entityUpstreamStepKey]['source_step_category_id'] = $StepCategoryId;
            $entityUpstreamStepIdMap[$entityUpstreamStepKey]['target_step_category_id'] = $entityTaskItem['step_category_id'];
            $returnData[] = $entityUpstreamStepIdMap[$entityUpstreamStepKey];
        }
        return $returnData;
    }


    /**
     * 获取关联类似是集的上游工序任务
     * @param $episodeUpstreamStepIdList
     * @param $episodeId
     * @param $projectId
     * @param $stepCategoryId
     * @param $type
     * @return array
     */
    public function getEpisodeUpstreamStepTaskList($episodeUpstreamStepIdList, $episodeId, $projectId, $stepCategoryId, $type): array
    {
        $upDownStreamIndex = 'upstream_step_id';
        if ($type == 'downstream') {
            $upDownStreamIndex = 'step_id';
        }
        $returnData = [];
        $episodeUpstreamStepIds = [];
        $episodeUpstreamStepIdMap = [];
        foreach ($episodeUpstreamStepIdList as $episodeUpstreamStepItem) {
            $episodeUpstreamStepKey = sprintf('step_id_%d', $episodeUpstreamStepItem[$upDownStreamIndex]);
            $episodeUpstreamStepIdMap[$episodeUpstreamStepKey] = $episodeUpstreamStepItem;
            $episodeUpstreamStepIds[] = $episodeUpstreamStepItem[$upDownStreamIndex];
        }
        $episodeTaskList = model(TaskModel::class)->forceMasterDB()
            ->where(['step_id' => ['IN', $episodeUpstreamStepIds]])
            ->where(['episode_id' => $episodeId])
            ->where(['project_id' => $projectId])
            ->select();
        if (empty($episodeTaskList)) {
            return $returnData;
        }
        foreach ($episodeTaskList as $episodeTaskItem) {
            $episodeUpstreamStepKey = sprintf('step_id_%d', $episodeTaskItem['step_id']);
            if (empty($episodeUpstreamStepIdMap[$episodeUpstreamStepKey])) {
                continue;
            }
            $episodeUpstreamStepIdMap[$episodeUpstreamStepKey]['upstream_task_id'] = $episodeTaskItem['id'];
            $episodeUpstreamStepIdMap[$episodeUpstreamStepKey]['upstream_task_info'] = $episodeTaskItem;
            $episodeUpstreamStepIdMap[$episodeUpstreamStepKey]['downstream_task_id'] = $episodeTaskItem['id'];
            $episodeUpstreamStepIdMap[$episodeUpstreamStepKey]['source_step_category_id'] = $stepCategoryId;
            $episodeUpstreamStepIdMap[$episodeUpstreamStepKey]['target_step_category_id'] = $episodeTaskItem['step_category_id'];
            $returnData[] = $episodeUpstreamStepIdMap[$episodeUpstreamStepKey];
        }
        return $returnData;
    }

    /**
     * 获取实体下的任务
     * @param $stepIds
     * @param $entityIds
     * @param $projectId
     * @return array|mixed|string
     */
    public function getEntityTaskIds($stepIds, $entityIds, $projectId)
    {
        $entityTaskList = model(TaskModel::class)
            ->forceMasterDB()
            ->where(['step_id' => ['IN', $stepIds]])
            ->where(['entity_id' => ['IN', $entityIds]])
            ->where(['project_id' => $projectId])
            ->select();
        if (empty($entityTaskList)) {
            return [];
        }
        return $entityTaskList;
    }


    /**
     * 获取关联实体
     * @param $entityId
     * @param $type
     * @return array|mixed|string
     */
    public function getRelationEntityIds($entityId, $type)
    {
        $where = ['entity_id' => $entityId];
        if ($type == 'downstream') {
            $where = ['relation_entity_id' => $entityId];
        }
        $entityList = model(EntityRelationshipsModel::class)
            ->forceMasterDB()
            ->where($where)
            ->field('relation_entity_id,entity_id')
            ->select();
        if (empty($entityList)) {
            return [];
        }
        $entityIds = [];
        foreach ($entityList as $entityItem) {
            if ($type == 'downstream') {
                $entityIds[] = $entityItem['entity_id'];
            } else {
                $entityIds[] = $entityItem['relation_entity_id'];
            }
        }
        return $entityIds;
    }

    /**
     * 根据任务id获取上游任务id
     * @param $filter
     * @param $fields
     * @param $projectId
     * @param $page
     * @return array
     */
    public function getTaskUpstreamByTaskIds($filter, $fields, $projectId, $page): array
    {
        if (empty($projectId)) {
            return [];
        }
        if (empty($fields)) {
            $fields = ['target_task_id', 'source_task_id'];
        }
        if (empty($page)) {
            $page = [1, C("database.database_max_select_rows")];
        }
        $upstreamTaskList = model(TaskRelationModel::class)
            ->setSuffix(sprintf('_project_%d', $projectId))
            ->where($filter)
            ->field($fields)
            ->page(...$page)
            ->select();
        if (empty($upstreamTaskList)) {
            return [];
        }
        return $upstreamTaskList;
    }

    /**
     * task_relation表 根据项目id分表
     * @return array
     */
    public function fixProjectIdByTaskRelationPartition(): array
    {
        $res = [];
        // 标准表
        $taskRelationTableName = model(TaskRelationModel::class)->getTableName();
        $createdPartitionTableList = model(TaskRelationModel::class)->query('SHOW CREATE TABLE ' . $taskRelationTableName);
        $createdPartitionTableListSql = $createdPartitionTableList[0]['create table'];
        if (empty($createdPartitionTableList[0]['create table'])) {
            return $res;
        }
        $projectList = model(ProjectModel::class)->field('id')->select();
        if (empty($projectList)) {
            return $res;
        }

        foreach ($projectList as $projectItem) {
            $newTableName = sprintf('task_relation_project_%d', $projectItem['id']);
            // 判断表是否存在
            $tableIsExists = Db::query('SHOW TABLES LIKE ' . "'$newTableName'");
            if (!empty($tableIsExists)) {
                continue;
            }
            $tmpCreatedPartitionTableListSql = str_replace('task_relation', $newTableName, $createdPartitionTableListSql);
            db::execute($tmpCreatedPartitionTableListSql);
            $res[] = $projectItem['id'];
        }

        return $res;
    }

    /**
     * 按照项目id填充数据task_relation分表数据
     * @return array
     */
    public function fixTaskProjectData(): array
    {
        $oldTaskRelation = model(TaskRelationModel::class)->group('project_id')->select();
        if (empty($oldTaskRelation)) {
            return [];
        }
        $res = [];
        // 按照项目id填充数据
        foreach ($oldTaskRelation as $taskRelationItem) {
            $tmpProjectId = $taskRelationItem['project_id'] ?? 0;
            $sql = "insert into task_relation_project_%d( source_task_id, target_task_id, uuid, relation_type, source_step_category_id, target_step_category_id, project_id, relation) select source_task_id, target_task_id, uuid, relation_type, source_step_category_id, target_step_category_id, project_id, relation from task_relation where project_id = %d";
            $tmpCreatedPartitionTableListSql = sprintf($sql, $tmpProjectId, $tmpProjectId);
            db::execute($tmpCreatedPartitionTableListSql);
        }
        return $res;
    }

    /**
     * 通过环节查找工单代办上游任务id
     * @param int $projectId
     * @param array $stepCategoryIds
     * @return array
     */
    public function getTaskWorkOrderStepCategoryUpstreamTaskIds(int $projectId, array $stepCategoryIds): array
    {
        $suffix = sprintf('_project_%d', $projectId);
        $res = model(TaskRelationModel::class)
            ->setSuffix($suffix)
            ->where(['relation_type' => TaskModel::STEP_TYPE_WORK_ORDER_TO_DO])
            ->where(['source_step_category_id' => ['IN', $stepCategoryIds]])
            ->field('id,source_task_id,target_task_id,source_step_category_id,target_step_category_id')
            ->select();
        if (empty($res)) {
            return [];
        }
        return $res;
    }
}
